package logica;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Random;

import value_objects.VoArma;
import value_objects.VoBarco;
import auxiliares.Configuracion;

public class Barco extends ObjetoMapeable {
	// Constantes
	public static final String PROPIEDAD_ARMA = "ARMA";
	public static final String PROPIEDAD_BLINDAJE = "BLINDAJE";
	public static final String PROPIEDAD_VELOCIDAD = "VELOCIDAD";

	public static final String BARCO_ROJO1 = "Rojo1";
	public static final String BARCO_AZUL1 = "Azul1";
	public static final String BARCO_AZUL2 = "Azul2";
	public static final String BARCO_AZUL3 = "Azul3";
	public static final String BARCO_VERDE1 = "Verde1";
	
	// Propiedades
	private int idTipoBarco;
	private int blindajeActual;
	private int velocidadActual;
	private int vida;
	private String nombre;
	private int sentidoPosicion;
	private int areaVisibilidad;
	private boolean movimientoHabilitado;
	private Integer dificultad;
	private Hashtable<Integer, Arma> hashArmas;
	
	/**
	 * Constructor por defecto
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public Barco() throws FileNotFoundException, IOException {
		super();
		hashArmas = new Hashtable<Integer, Arma>();
		dificultad = 1;
		inicializar();
	}

	/**
	 * Constructor normal a partir del nombre del barco y la dificultad elegida. 
	 * @param _nombre
	 * @param _dificultad
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public Barco(String _nombre, Integer _dificultad) throws FileNotFoundException, IOException {
		super();
		hashArmas = new Hashtable<Integer, Arma>();
		nombre = _nombre;
		dificultad = _dificultad;
		inicializar();
	}

	/**
	 * 
	 * @param nombreBarco
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public void inicializar() throws FileNotFoundException, IOException {
		//Cargar Properties del barco segun configuracion
		
		// TODO Cambiar nombres de variable p, k, n y m para que sean nemotécnicas
		Configuracion barcoBase = Configuracion.getInstancia(Configuracion.CONFIGURACION_BARCOS_BASE);
		Configuracion p = Configuracion.getInstancia(Configuracion.CONFIGURACION_BARCOS);
		Configuracion k = Configuracion.getInstancia(Configuracion.CONFIGURACION_POSICIONES);
		Configuracion multiplicador = Configuracion.getInstancia(Configuracion.CONFIGURACION_MULTIPLICADORES);
		
		Integer tipoConfig = (int) Math.floor(Math.random() * 3) + 1;
		
		int posicionX = Integer.parseInt(k.getProperty(nombre + "CoordX" + tipoConfig).trim());
		int posicionY = Integer.parseInt(k.getProperty(nombre + "CoordY" + tipoConfig).trim());
		setPosicion(posicionX, posicionY);
		
		setIdTipoBarco(Integer.parseInt(p.getProperty(nombre + "idTipoBarco")));
		
		setLargo(Integer.parseInt(p.getProperty(nombre + "largo").trim()));
		setAncho(Integer.parseInt(p.getProperty(nombre + "ancho").trim()));
		setBlindajeActual(Math.round(
			Integer.parseInt(barcoBase.getProperty("blindaje" + dificultad).trim()) *
			Float.parseFloat(multiplicador.getProperty("blindaje" + idTipoBarco).trim())
		));
		setVelocidadActual(Math.round(
			Integer.parseInt(barcoBase.getProperty("velocidad" + dificultad).trim()) *
			Float.parseFloat(multiplicador.getProperty("velocidad" + idTipoBarco).trim())
		));
		setAreaVisibilidad(Math.round(
			Integer.parseInt(barcoBase.getProperty("areaVisibilidad" + dificultad).trim()) *
			Float.parseFloat(multiplicador.getProperty("areaVisibilidad" + idTipoBarco).trim())
		));
		setVida(Math.round(
			Integer.parseInt(barcoBase.getProperty("vida" + dificultad).trim()) *
			Float.parseFloat(multiplicador.getProperty("vida" + idTipoBarco).trim())
		));

		setSentidoPosicionSinArmas(Integer.parseInt(p.getProperty(nombre + "sentidoPosicion").trim())); 
		Integer cantidadArmas = Integer.parseInt(p.getProperty(nombre + "cantidadArmas").trim());
		setMovimientoHabilitado(Boolean.parseBoolean(p.getProperty(nombre + "movimientoHabilitado").trim()));

		// Hashtable<Integer, Arma> hashArmas = new Hashtable<Integer, Arma>();
		int coordXarma = 0;
		int coordYarma = 0;

		for (Integer i = 1; i <= cantidadArmas; i++) {
			int pos = Integer.parseInt(p.getProperty(nombre + "Arma" + i + "Posicion").trim());
			int tipo = Integer.parseInt(p.getProperty(nombre + "Arma" + i + "Tipo").trim());
			switch (pos) {
				case 1: //En la proa
					coordXarma = Math.round((posicionX + (getLargo() / 2)));
				    coordYarma = Math.round((posicionY + (getAncho() / 2)));
				break;
				case 2: //En la popa
					coordXarma = Math.round((posicionX - (getLargo() / 2)));
			        coordYarma = Math.round((posicionY - (getAncho() / 2)));
				break;
				case 3: //En el medio
					coordXarma = Math.round((posicionX));
			        coordYarma = Math.round((posicionY));
			    break;
			}
			Arma arma = new Arma(tipo);
			arma.inicializar(idTipoBarco);
			arma.setPosicion(coordXarma, coordYarma);
			hashArmas.put(arma.getIdTipoArma(), arma);
		}
	}
	
	/**
	 * Daña las armas de este barco 
	 * @param _danioArmas
	 * @param _danioAlcance
	 */
	public void danioArmas (int _danioArmas, int _danioAlcance) {
		Iterator<Arma> itArmas = getArmas();
		int x = 0, danMun = 0, z = 0, danAlc = 0;
		Random randMuni = new Random(), randAlcance = new Random();
		x = randMuni.nextInt(_danioArmas);
		z = randAlcance.nextInt(_danioAlcance);
		danMun = _danioArmas - x;
		danAlc = _danioAlcance - z;
		while ( itArmas.hasNext() ) {
			Arma arma = itArmas.next();
			if ( !arma.getNombre().equals("Torpedo")) {
				arma.getDanioArmas().setDanioCantMuniciones(arma.getCantMunicionActual() - x);
				arma.getDanioArmas().setDanioAlcance(arma.getAlcanceActual() - z);
				arma = itArmas.next();
				arma.getDanioArmas().setDanioCantMuniciones(arma.getCantMunicionActual() - danMun);
				arma.getDanioArmas().setDanioAlcance(arma.getAlcanceActual() - danAlc);
			}
		}
	}
	
	/**
	 * Devuelve el blindaje máximo del barco
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public int darBlindajeMaximo() throws FileNotFoundException, IOException {
		Configuracion barcoBase = Configuracion.getInstancia(Configuracion.CONFIGURACION_BARCOS_BASE);
		Configuracion multiplicador = Configuracion.getInstancia(Configuracion.CONFIGURACION_MULTIPLICADORES);
		return Math.round(
			Integer.parseInt(barcoBase.getProperty("blindaje" + dificultad).trim()) *
			Float.parseFloat(multiplicador.getProperty("blindaje" + idTipoBarco).trim())
		);
	}
	
	/**
	 * Devuelve la velocidad máxima de este barco
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public int darVelocidadMaxima() throws FileNotFoundException, IOException {
		Configuracion barcoBase = Configuracion.getInstancia(Configuracion.CONFIGURACION_BARCOS_BASE);
		Configuracion multiplicador = Configuracion.getInstancia(Configuracion.CONFIGURACION_MULTIPLICADORES);
		return Math.round(
			Integer.parseInt(barcoBase.getProperty("velocidad" + dificultad).trim()) *
			Float.parseFloat(multiplicador.getProperty("velocidad" + idTipoBarco).trim())
		);
	}
	
	/**
	 * Devuelve la información del barco útil para el cliente.
	 * @return
	 */
	public VoBarco obtenerInfoBarco() {
		Iterator<Arma> armas = getArmas();
		VoArma[] datosArmas = new VoArma[getHashArmas().size()];
		int i=0;
		while (armas.hasNext()) {
			datosArmas[i]=armas.next().obtenerInfoArma();
			i++;
		}
		//TODO: Revisar ancho y alto
		return (new VoBarco(getNombre(), getIdTipoBarco(), getPosicion(), getVida() > 0, getMovimientoHabilitado(), 
			   getVida(), getBlindajeActual(), getVelocidadActual(), getSentidoPosicion(), getLargo(),
			   getAncho(), datosArmas));
	}

	/**
	 * devuelve un string conteniendo todas las propiedades del barco en formato xml.
	 * @param nombreBando
	 * @return
	 */
	public String getXML(String nombreBando) {
		String movimiento = "false";
		if (getMovimientoHabilitado()) {
			movimiento = "true";
		}
		String datosBarco = 
			"<Barco" + nombreBando + ">" +
			"<NombreBarco>" + getNombre() + "</NombreBarco>" +
			"<IdTipoBarco>" + getIdTipoBarco() + "</IdTipoBarco>" +
			"<Largo>" + getLargo() + "</Largo>" +
			"<Ancho>" + getAncho() + "</Ancho>" +
			"<Visibilidad>" + getAreaVisibilidad() + "</Visibilidad>" +
			"<BlindajeActual>" + getBlindajeActual() + "</BlindajeActual>" +
			"<VelocidadActual>" + getVelocidadActual() + "</VelocidadActual>" +
			"<SentidoPosicion>" + getSentidoPosicion() + "</SentidoPosicion>" +
			"<Vida>" + getVida() + "</Vida>" +
			"<PosX>" + getPosicion().getCoordX() + "</PosX>"+
			"<PosY>" + getPosicion().getCoordY() + "</PosY>"+
			"<MovimientoHabilitado>" + movimiento + "</MovimientoHabilitado>" +
			"<Armas>"; 
		
		//BARCOS
	    Iterator<Arma> armas = getArmas();
	    while (armas.hasNext()) {
	    	datosBarco = datosBarco + armas.next().getXML(getNombre());
	    }
		return datosBarco+"</Armas></Barco" + nombreBando + ">" ;
	}
	
	/**
	 * Actualiza las coordenadas de las armas del barco
	 */
	/*
	private void actualizarCoordenadasArmas () {
		int ancho = getLargo(), alto = getAncho();
		Iterator<Arma> itArma = getArmas();
		Arma _arma1 = itArma.next(), _arma2 = itArma.next(), _arma3 = itArma.next();
		if (sentidoPosicion != 0) {
				double radianesAngulo = sentidoPosicion * Math.PI / 180,
					   radianesAngulo2 = (sentidoPosicion + 90) % 360 * Math.PI / 180; 
				double x1, x2, y1, y2;
				x1 = (ancho / 2) * Math.cos(radianesAngulo);
				x2 = (alto / 2) * Math.cos(radianesAngulo2);
				y1 = (ancho / 2) * Math.sin(radianesAngulo);
				y2 = (alto / 2) * Math.sin(radianesAngulo2);
				if (sentidoPosicion < 90) {
					x1 = Math.abs(x1) + Math.abs(x2);
					y1 = Math.abs(y1) - Math.abs(y2);
					if (_arma1.getPosicion().getCoordX() > _arma2.getPosicion().getCoordX() ) { 
						getArma(_arma1.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (int) x1, getPosicion().getCoordY() + (int) y1));
						getArma(_arma2.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() - (int) x1, getPosicion().getCoordY() - (int) y1)); 				
						getArma(_arma3.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (int) x1, getPosicion().getCoordY() + (int) y1));
					}
				} else if (sentidoPosicion < 180) {
					x1 = Math.abs(x1) - Math.abs(x2);
					y1 = Math.abs(y1) + Math.abs(y2);
					getArma(_arma1.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() - (int)x1, getPosicion().getCoordY() + (int)y1));
					getArma(_arma2.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (int)x1, getPosicion().getCoordY() - (int)y1)); 				
					getArma(_arma3.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() - (int)x1, getPosicion().getCoordY() + (int)y1));					
				} else if (sentidoPosicion < 270) {
					x1 = Math.abs(x1) - Math.abs(x2);
					y1 = Math.abs(y1) + Math.abs(y2);
					getArma(_arma1.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() - (int)x1, getPosicion().getCoordY() - (int)y1));
					getArma(_arma2.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (int)x1, getPosicion().getCoordY() + (int)y1)); 				
					getArma(_arma3.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() - (int)x1, getPosicion().getCoordY() - (int)y1));
				} else {
					x1 = Math.abs(x1) - Math.abs(x2);
					y1 = Math.abs(y1) + Math.abs(y2);
					getArma(_arma1.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (int)x1, getPosicion().getCoordY() - (int)y1));
					getArma(_arma2.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() - (int)x1, getPosicion().getCoordY() + (int)y1)); 				
					getArma(_arma3.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (int)x1, getPosicion().getCoordY() - (int)y1));
				}
		} else if ( _arma1.getPosicion().getCoordX() > _arma2.getPosicion().getCoordX() ) { 
				getArma(_arma1.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (ancho / 2), getPosicion().getCoordY()));
				getArma(_arma2.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() - (ancho / 2), getPosicion().getCoordY())); 				
				getArma(_arma3.getIdTipoArma()).setPosicion(new Coordenada(getPosicion().getCoordX() + (ancho / 2), getPosicion().getCoordY()));
		}
	}*/

	// ********************* GETTERS Y SETTERS *********************
	
	public int getIdTipoBarco() {
		return idTipoBarco;
	}
	
	public void setIdTipoBarco(int _idTipoBarco) {
		this.idTipoBarco = _idTipoBarco;
	}

	public int getBlindajeActual() {
		return blindajeActual;
	}

	public void setBlindajeActual(int _blindajeActual) {
		this.blindajeActual = _blindajeActual;
	}

	public int getVelocidadActual() {
		return velocidadActual;
	}

	public void setVelocidadActual(int _velocidadActual) {
		this.velocidadActual = _velocidadActual;
	}

	public int getVida() {
		return vida;
	}

	public void setVida(int _vida) {
		this.vida = _vida;
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String _nombre) {
		this.nombre = _nombre;
	}

	public int getSentidoPosicion() {
		return sentidoPosicion;
	}

	public void setSentidoPosicion(int _sentidoPosicion) {
		this.sentidoPosicion = _sentidoPosicion;
		//actualizarCoordenadasArmas();
	}
	public void setSentidoPosicionSinArmas(int _sentidoPosicion) {
		this.sentidoPosicion = _sentidoPosicion;
	}

	public int getAreaVisibilidad() {
		return areaVisibilidad;
	}

	public void setAreaVisibilidad(int _areaVisibilidad) {
		this.areaVisibilidad = _areaVisibilidad;
	}
	
	public void agregarArma(Arma _arma) {
		this.hashArmas.put(_arma.getIdTipoArma(),_arma);
	}
	
	public Arma getArma(int _idTipoArma) {
		return hashArmas.get(_idTipoArma);
	}
	
	public Iterator<Arma> getArmas() {
		return hashArmas.values().iterator();
	}

	public Hashtable<Integer, Arma> getHashArmas() {
		return hashArmas;
	}

	public void setHashArmas(Hashtable<Integer, Arma> hashArmas) {
		this.hashArmas = hashArmas;
	}

	public void setMovimientoHabilitado(boolean movimientoHabilitado) {
		this.movimientoHabilitado = movimientoHabilitado;
	}

	public boolean getMovimientoHabilitado() {
		return movimientoHabilitado;
	}
}